/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.navid.trafalgar.model;

import com.jme3.asset.AssetManager;
import com.jme3.input.InputManager;
import com.jme3.input.controls.AnalogListener;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.navid.trafalgar.persistence.CandidateRecord;
import com.navid.trafalgar.persistence.StepRecord;

/**
 *
 * @author alberto
 */
public abstract class AShipZeroModel extends AShipModel {

    public static class ShipCandidateRecord extends CandidateRecord<ShipSnapshot> {
    }

    public static class ShipSnapshot extends StepRecord {

        private Vector3f position;
        private Quaternion rotation;

        private void setPosition(Vector3f position) {
            this.position = position;
        }

        private void setRotation(Quaternion rotation) {
            this.rotation = rotation;
        }

        public Vector3f getPosition() {
            return position;
        }

        public Quaternion getRotation() {
            return rotation;
        }
    }

    protected abstract class Sail extends TrafalgarNode{

        protected Sail(AssetManager assetManager) {
            super(new Vector3f(1,0,0), assetManager);
            initGeometry();
        }

        protected abstract void initGeometry();


        public final void rotateY(float radians) {
            this.rotate(0, radians, 0);
        }
    }

    protected abstract class Rudder {

        private Vector2f orientation = new Vector2f(1, 0);
        protected Node spatialRudder = new Node();

        protected Rudder(AssetManager assetManager) {
            initGeometry();
        }
        
        protected abstract void initGeometry();

        public final Vector2f getLocalOrientation() {
            return orientation;
        }

        public final void setLocalOrientation(Vector2f newOrientation) {
            float radians = this.orientation.angleBetween(newOrientation);
            rotate(-radians);
        }

        public final void rotate(float radians) {
            orientation.rotateAroundOrigin(radians, true);
        }

        private void resetRotation() {
            setLocalOrientation(new Vector2f(1, 0));
        }
        
        public final Spatial getSpatial() {
            return spatialRudder;
        }
    }
    
    protected Spatial spatial;
    protected Sail sail;
    protected Rudder rudder;
    //private Vector2f shipOrientation = new Vector2f(1, 0);
    private float speed = 0f;
    private Material matHull;
    private Material matSail;
    private float rudderRotation;
    private float sailRotation;
    private boolean previousTransparent = false;

    public AShipZeroModel(AssetManager assetManager) {
        super(new Vector3f(1,0,0),assetManager );

        initGeometry(assetManager);
        
        this.attachChild(sail);
        this.attachChild(rudder.getSpatial());

        spatial.setQueueBucket(Bucket.Transparent);
        sail.setQueueBucket(Bucket.Transparent);
    }

    protected abstract void initGeometry(AssetManager assetManager);

    public final void update(float tpf) {

        if (rudderRotation == 0) {
            rudder.resetRotation();
        } else {
            rudder.rotate(rudderRotation);
        }
        rudderRotation = 0;

        sail.rotateY(sailRotation * 50);
        sailRotation = 0;

        Vector3f windDirection = new Vector3f( context.getWind().getWind().x, 0, context.getWind().getWind().y);
        Vector3f shipOrientation3f = this.getGlobalDirection();

        double windOverVela = Math.cos(sail.getGlobalDirection().angleBetween( windDirection));
        double velaOverShip = Math.cos(shipOrientation3f.angleBetween(sail.getGlobalDirection()));

        float speed_gain = (float) (windDirection.length() * windOverVela * velaOverShip * tpf * 100);

        speed = (speed * 500 + speed_gain) / 501;

        this.rotate(0, rudder.getLocalOrientation().getAngle() * speed, 0);

        this.move(shipOrientation3f.x * speed, 0, shipOrientation3f.z * speed);

    }

    public final Control cloneForSpatial(Spatial spatial) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public final void setSpatial(Spatial spatial) {
    }

    public final void render(RenderManager rm, ViewPort vp) {
    }
    
    private final AnalogListener analogListener = new AnalogListener() {

        public void onAnalog(String name, float value, float tpf) {

            if (name.equals("SHIP_RudderRight")) {
                rudderRotation = value * tpf;
            }
            if (name.equals("SHIP_RudderLeft")) {
                rudderRotation = -value * tpf;
            }
            if (name.equals("SHIP_SailRight")) {
                sailRotation = value * tpf;
            }
            if (name.equals("SHIP_SailLeft")) {
                sailRotation = -value * tpf;
            }

        }
    };

    @Override
    public final void registerInput(InputManager inputManager) {
        inputManager.addListener(analogListener, new String[]{"SHIP_RudderRight", "SHIP_RudderLeft", "SHIP_SailRight", "SHIP_SailLeft"});
    }

    @Override
    public final float getSpeed() {
        return speed;
    }

    public final void setSailMaterial(Material mat) {
        matSail = mat;
        sail.setMaterial(mat);
    }

    public final void setHullMaterial(Material mat) {
        matHull = mat;
        spatial.setMaterial(mat);
    }

    @Override
    public final void setTransparent(boolean b) {
        if (!previousTransparent && b) {
            matHull.getAdditionalRenderState().setBlendMode(BlendMode.Color); // activate transparency
            matSail.getAdditionalRenderState().setBlendMode(BlendMode.Color); // activate transparency
            previousTransparent = true;

        } else if (!b && previousTransparent) {
            matHull.getAdditionalRenderState().setBlendMode(BlendMode.Off); // activate transparency
            matSail.getAdditionalRenderState().setBlendMode(BlendMode.Off); // activate transparency
            previousTransparent = false;
        }
    }

    @Override
    public final StepRecord getSnapshot() {
        ShipSnapshot snapshot = new ShipSnapshot();

        snapshot.setPosition(this.getLocalTranslation().clone());
        snapshot.setRotation(this.getLocalRotation().clone());

        return snapshot;
    }

    @Override
    public final void updateFromRecord(StepRecord currentStepRecord) {

        ShipSnapshot snapshot = (ShipSnapshot) currentStepRecord;

        this.setLocalTranslation(snapshot.getPosition());
        this.setLocalRotation(snapshot.getRotation());

    }

    @Override
    public final CandidateRecord getCandidateRecordInstance() {
        return new ShipCandidateRecord();
    }
}
